__author__ = 'cain76'
# // Planets.c
# // OpenGL SuperBible
# // Richard S. Wright Jr.
# // rwright@starstonesoftware.com
#
# #include "../../shared/gltools.h"	// OpenGL toolkit


# Import OpenGL
try:
    import OpenGL
    from OpenGL.GL import *
    from OpenGL.GLU import *
    from OpenGL.GLUT import *

    try: glutInit()
    except: print("Warning: OpenGL.GLUT initialization failed")
    print('Import OpenGL(GL, GLU)')
except:
    raise GLError("Error: PyOpenGL not available")

# ///////////////////////////////
# // Define object names
SUN = 1
MERCURY = 2
VENUS = 3
EARTH = 4
MARS = 5

rot = 0.0

# ///////////////////////////////////////////////////////////
# // Just draw a sphere of some given radius
def DrawSphere(radius):
    # {
    # pObj = GLUquadricObj
    pObj = gluNewQuadric()
    gluQuadricNormals(pObj, GLU_SMOOTH)
    gluSphere(pObj, radius, 26, 13)
    gluDeleteQuadric(pObj)
    # }


def RenderScene():
    # {
    global rot
    # // Clear the window with current clearing color
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    # // Save the matrix state and do the rotations
    glMatrixMode(GL_MODELVIEW)
    glPushMatrix()
    # // Translate the whole scene out and into view
    # glTranslatef(0.0, 0.0, -300.0)
    gluLookAt(0,100,300,
              0,0,0,
              0,1,0)
    glRotatef(rot, 0,1,0)
    # // Initialize the names stack
    glInitNames()
    glPushName(0)

    # // Name and draw the Sun
    glColor3f(1.0, 1.0, 0.0)
    glLoadName(SUN)
    DrawSphere(15.0)

    # // Draw Mercury
    glColor3f(0.5, 0.0, 0.0)
    glPushMatrix()
    glTranslatef(24.0, 0.0, 0.0)
    glLoadName(MERCURY)
    DrawSphere(2.0)
    glPopMatrix()

    # // Draw Venus
    glColor3f(0.5, 0.5, 1.0)
    glPushMatrix()
    glTranslatef(60.0, 0.0, 0.0)
    glLoadName(VENUS)
    DrawSphere(4.0)
    glPopMatrix()

    # // Draw the Earth
    glColor3f(0.0, 0.0, 1.0)
    glPushMatrix()
    glTranslatef(100.0, 0.0, 0.0)
    glLoadName(EARTH)
    DrawSphere(8.0)
    glPopMatrix()

    # // Draw Mars
    glColor3f(1.0, 0.0, 0.0)
    glPushMatrix()
    glTranslatef(150.0, 0.0, 0.0)
    glLoadName(MARS)
    DrawSphere(4.0)
    glPopMatrix()

    # // Restore the matrix state
    glPopMatrix()  # // Modelview matrix

    glutSwapBuffers()
    # }


# ///////////////////////////////////////////////////////////
# // Present the information on which planet/sun was selected
# // and displayed
def ProcessPlanet(idx):
    # {
    if idx == SUN: msg = "You clicked on the Sun!"
    elif idx == MERCURY: msg = "You clicked on Mercury!"
    elif idx == VENUS: msg = "You clicked on Venus!"
    elif idx == EARTH: msg = "You clicked on Earth!"
    elif idx == MARS: msg = "You clicked on Mars!"
    else: msg = "Nothing was clicked on!"
    glutSetWindowTitle(msg)
    print(msg)
    # }


# ///////////////////////////////////////////////////////////
# // Process the selection, which is triggered by a right mouse
# // click at (xPos, yPos).
# define BUFFER_LENGTH 64
def ProcessSelection(xPos, yPos):
    # {
    # global selectBuff
    # GLfloat fAspect

    # // Space for selection buffer
    # static GLuint selectBuff[BUFFER_LENGTH]

    # // Hit counter and viewport storage
    # GLint hits, viewport[4]
    iarray = ctypes.c_int * 64
    selectBuff = iarray(0, )

    # // Setup selection buffer
    glSelectBuffer(64, selectBuff)

    # // Get the viewport
    viewport = glGetIntegerv(GL_VIEWPORT)

    # // Switch to projection and save the matrix
    glMatrixMode(GL_PROJECTION)
    glPushMatrix()

    # // Change render mode
    glRenderMode(GL_SELECT)

    # // Establish new clipping volume to be unit cube around
    # // mouse cursor point (xPos, yPos) and extending two pixels
    # // in the vertical and horizontal direction
    glLoadIdentity()
    gluPickMatrix(xPos, viewport[3] - yPos + viewport[1], 2, 2, viewport)

    # // Apply perspective matrix
    fAspect = viewport[2] / viewport[3]
    gluPerspective(45.0, fAspect, 1.0, 425.0)

    # // Draw the scene
    RenderScene()

    # // Collect the hits
    hits = glRenderMode(GL_RENDER)

    nErr = glGetError()
    # // If a single hit occurred, display the info.
    if hits == 1:
        ProcessPlanet(selectBuff[3])
    else:
        glutSetWindowTitle("Nothing was clicked on!")

    for i in range(len(hits)):
        print(hits[i])

    for i in range(64):
        print(selectBuff[i], end=',')
    print('')

    # // Restore the projection matrix
    glMatrixMode(GL_PROJECTION)
    glPopMatrix()

    # // Go back to modelview for normal rendering
    glMatrixMode(GL_MODELVIEW)
    # }


# ///////////////////////////////////////////////////////////
# // Process the mouse click
def MouseCallback(button, state, x, y):
    # {
    if button == GLUT_LEFT_BUTTON and state == GLUT_DOWN:
        ProcessSelection(x, y)
        # }


# ///////////////////////////////////////////////////////////
# // This function does any needed initialization on the
# // rendering context.
def SetupRC():
    # {
    # // Lighting values
    dimLight = [0.1, 0.1, 0.1, 1.0]
    sourceLight = [0.65, 0.65, 0.65, 1.0]
    lightPos = [0.0, 0.0, 0.0, 1.0]

    # // Light values and coordinates
    glEnable(GL_DEPTH_TEST)  # // Hidden surface removal
    glFrontFace(GL_CCW)  # // Counter clock-wise polygons face out
    glEnable(GL_CULL_FACE)  # // Do not calculate insides

    # // Enable lighting
    glEnable(GL_LIGHTING)

    # // Setup and enable light 0
    glLightfv(GL_LIGHT0, GL_AMBIENT, dimLight)
    glLightfv(GL_LIGHT0, GL_DIFFUSE, sourceLight)
    glLightfv(GL_LIGHT0, GL_POSITION, lightPos)
    glEnable(GL_LIGHT0)

    # // Enable color tracking
    glEnable(GL_COLOR_MATERIAL)

    # // Set Material properties to follow glColor values
    glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE)

    # // Gray background
    glClearColor(0.60, 0.60, 0.60, 1.0)
    # }


# ///////////////////////////////////////////////////////////
# // Window changed size, reset viewport and projection
def ChangeSize(ww, hh):
    # {
    # GLfloat fAspect

    # // Prevent a divide by zero
    if hh == 0: hh = 1

    # // Set Viewport to window dimensions
    glViewport(0, 0, ww, hh)

    # // Calculate aspect ratio of the window
    fAspect = ww / hh

    # // Set the perspective coordinate system
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()

    # // Field of view of 45 degrees, near and far planes 1.0 and 425
    gluPerspective(45.0, fAspect, 1.0, 425.0)

    # // Modelview matrix reset
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    # }


def Idle():
    global rot
    rot += 1.0
    glutPostRedisplay()

def main():
    # {
    # glutInit(&argc, argv)
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
    glutInitWindowSize(800, 600)
    glutCreateWindow("Pick a Planet")
    glutReshapeFunc(ChangeSize)
    glutMouseFunc(MouseCallback)
    glutDisplayFunc(RenderScene)
    glutIdleFunc(Idle)
    SetupRC()
    glutMainLoop()

    return 0
    # }


main()
